// Hardware Buffer Array
// (c) jimon game studio

#include "CHardwareBufferArray_OpenGL.h"
#include "CHardwareBuffer_OpenGL.h"

#ifdef JE_RENDER_OPENGL

namespace je
{
	namespace video
	{
		//! Constructor
		CHardwareBufferArray_OpenGL::CHardwareBufferArray_OpenGL(CRender_OpenGL_Extensions * NewExtensions)
			:Extensions(NewExtensions)
		{
		}

		//! Destructor
		CHardwareBufferArray_OpenGL::~CHardwareBufferArray_OpenGL()
		{
			Extensions->BindBuffer(GL_ARRAY_BUFFER,NULL);
			Extensions->BindBuffer(GL_ELEMENT_ARRAY_BUFFER,NULL);

			for(s32 i=0;i<JE_MAX_SHADER_VERTEX_LAYERS;i++)
				Extensions->DisableVertexAttributeArray(i);

			for(s32 i=0;i<JE_MAX_SHADER_VERTEX_LAYERS+1;i++)
				if(Buffers[i].Buffer)
					Buffers[i].Buffer->Drop();
		}

		//! Attach Hardware Buffer
		void CHardwareBufferArray_OpenGL::AttachBuffer(IHardwareBuffer * Buffer,HardwareBufferArrayLayers Layer,s32 VariablesPerObject,s32 VariableSize,s32 Stride,s32 Offset,u1 ThisIsIntFormat)
		{
			JEASSERT(Buffer)

			if(Buffers[Layer].Buffer)
				Buffers[Layer].Buffer->Drop();

			Buffers[Layer].Buffer = Buffer;

			if(Buffers[Layer].Buffer)
				Buffers[Layer].Buffer->Grab();

			Buffers[Layer].VariablesPerObject = VariablesPerObject;
			Buffers[Layer].VariableSize = VariableSize;
			if(Stride > 0)
				Buffers[Layer].Stride = Stride;
			else
				Buffers[Layer].Stride = VariablesPerObject * VariableSize;
			Buffers[Layer].Offset = Offset;
			Buffers[Layer].ThisIsIntFormat = ThisIsIntFormat;

			switch(Layer)
			{
			case HBAL_POSITION:
				VertexObjectCount = Buffer->GetSize() / Buffers[Layer].Stride;
				break;
			case HBAL_INDEXES:
				{
					IndexObjectCount = Buffer->GetSize() / Buffers[Layer].Stride;

					switch(VariableSize)
					{
					case 1:
						IndexType = GL_UNSIGNED_BYTE;
						break;
					case 2:
						IndexType = GL_UNSIGNED_SHORT;
						break;
					case 4:
						IndexType = GL_UNSIGNED_INT;
						break;
					default:
						JELOG_E(jeStringc("Unsuported index size : ")+jeStringc(VariableSize))
						IndexType = GL_NONE;
						break;
					}
					break;
				}
			default:
				break;
			}
		}

		//! Get Layer Info
		IHardwareBufferArray::LayerInfo & CHardwareBufferArray_OpenGL::GetLayerInfo(HardwareBufferArrayLayers Layer)
		{
			return Buffers[Layer];
		}

		//! Update layers
		void CHardwareBufferArray_OpenGL::UpdateLayers()
		{
			VertexObjectCount = Buffers[HBAL_POSITION].Buffer->GetSize() / Buffers[HBAL_POSITION].Stride;

			IndexObjectCount = Buffers[HBAL_INDEXES].Buffer->GetSize() / Buffers[HBAL_INDEXES].Stride;

			switch(Buffers[HBAL_INDEXES].VariableSize)
			{
			case 1:
				IndexType = GL_UNSIGNED_BYTE;
				break;
			case 2:
				IndexType = GL_UNSIGNED_SHORT;
				break;
			case 4:
				IndexType = GL_UNSIGNED_INT;
				break;
			default:
				JELOG_E(jeStringc("Unsuported index size : ")+jeStringc(Buffers[HBAL_INDEXES].VariableSize))
				IndexType = GL_NONE;
				break;
			}
		}

		//! Bind
		void CHardwareBufferArray_OpenGL::Bind(CShaderMaterial_OpenGL * ShaderMaterial)
		{
			Extensions->BindBuffer(GL_ELEMENT_ARRAY_BUFFER,static_cast<CHardwareBuffer_OpenGL*>(Buffers[HBAL_INDEXES].Buffer)->GetVboId());

			IHardwareBuffer * LastBuffer = NULL;

			for(s32 i=0;i<JE_MAX_SHADER_VERTEX_LAYERS;i++)
			{
				if(Buffers[i].Buffer)
				{
					if(LastBuffer != Buffers[i].Buffer)
					{
						Extensions->BindBuffer(GL_ARRAY_BUFFER,static_cast<CHardwareBuffer_OpenGL*>(Buffers[i].Buffer)->GetVboId());
						LastBuffer = Buffers[i].Buffer;
					}
					GLenum Type = 0;
					switch(Buffers[i].VariableSize)
					{
					case 1:
						Type = GL_UNSIGNED_BYTE;
						break;
					case 2:
						Type = GL_SHORT;
						break;
					case 4:
						Type = GL_FLOAT;
						break;
					case 8:
						Type = GL_DOUBLE;
						break;
					}
					if(Buffers[i].ThisIsIntFormat && (Buffers[i].VariableSize == 4))
						Type = GL_INT;
					ShaderMaterial->SetVertexAttribute((HardwareBufferArrayLayers)i,true,Buffers[i].VariablesPerObject,Type,false,Buffers[i].Stride,(c8*)NULL+Buffers[i].Offset);
				}
				else
					ShaderMaterial->SetVertexAttribute((HardwareBufferArrayLayers)i,false);
			}
		}
	}
}

#endif
